import { CodeMirror } from "vue-codemirror";

CodeMirror.extendMode("css", {
  commentStart: "/*",
  commentEnd: "*/",
  newlineAfterToken: function(type, content) {
    return /^[;{}]$/.test(content);
  }
});

CodeMirror.extendMode("javascript", {
  commentStart: "/*",
  commentEnd: "*/",
  // FIXME semicolons inside of for
  newlineAfterToken: function(type, content, textAfter, state) {
    if (this.jsonMode) {
      return /^[\[,{]$/.test(content) || /^}/.test(textAfter);
    } else {
      if (content == ";" && state.lexical && state.lexical.type == ")")
        return false;
      return /^[;{}]$/.test(content) && !/^;/.test(textAfter);
    }
  }
});

function dealEndTag(str) {
  let lTagIndex = str.lastIndexOf("<");
  if (lTagIndex === -1) {
    return false;
  } else {
    let slashIndex = lTagIndex + 1;
    if (str[slashIndex] === "/") {
      return true;
    } else {
      return false;
    }
  }
}

CodeMirror.extendMode("xml", {
  commentStart: "<!--",
  commentEnd: "-->",
  newlineAfterToken: function(type, content, textAfter, textBefore) {
    let flag = false;

    if (content == "/>") {
      return true;
    }

    if (type == null) {
      if (content.trim() == "") {
        // 空格的情况
        if (textAfter.indexOf("</") !== -1) {
          if (textBefore.indexOf("</") !== -1) {
            flag = true;
          } else {
            flag = false;
          }
        } else if (textAfter.indexOf("<") !== -1) {
          // < 换行
          flag = true;
        } else {
          flag = false;
        }
      }
      flag = false;
    }

    if ((type == "tag" || type === "tag bracket") && />$/.test(content)) {
      if (/^<\//.test(textAfter.trim())) {
        return dealEndTag(textBefore);
      } else {
        if (!/^</.test(textAfter.trim())) {
          flag = false;
        } else {
          flag = true;
        }
      }
    } else {
      flag = false;
    }

    return flag;
  }
});

// Applies automatic mode-aware indentation to the specified range
CodeMirror.defineExtension("autoIndentRange", function(from, to) {
  var cmInstance = this;
  this.operation(function() {
    for (var i = from.line; i <= to.line; i++) {
      cmInstance.indentLine(i, "smart");
    }
  });
});

// Applies automatic formatting to the specified range
CodeMirror.defineExtension("autoFormatRange", function(from, to) {
  var cm = this;
  var outer = cm.getMode(),
    text = cm
      .getRange(from, to)
      .replace(/\t/g, "")
      .split("\n");
  var state = CodeMirror.copyState(outer, cm.getTokenAt(from).state);
  var tabSize = cm.getOption("tabSize");

  var out = "",
    lines = 0,
    atSol = from.ch == 0;
  function newline() {
    out += "\n";
    atSol = true;
    ++lines;
  }
  for (var i = 0; i < text.length; ++i) {
    var stream = new CodeMirror.StringStream(text[i], tabSize);
    while (!stream.eol()) {
      var inner = CodeMirror.innerMode(outer, state);
      var style = outer.token(stream, state),
        cur = stream.current();
      stream.start = stream.pos;
      if (!atSol || /\S/.test(cur)) {
        out += cur;
        atSol = false;
      }
      if (
        !atSol &&
        inner.mode.newlineAfterToken &&
        inner.mode.newlineAfterToken(
          style,
          cur,
          stream.string.slice(stream.pos) || text[i + 1] || "",
          stream.string.slice(0, stream.pos) || text[i + 1] || "",
          inner.state
        )
      )
        newline();
    }
    if (!stream.pos && outer.blankLine) outer.blankLine(state);
    // if (!atSol) newline();
  }

  cm.operation(function() {
    cm.replaceRange(out, from, to);
    for (var cur = from.line + 1, end = from.line + lines; cur <= end; ++cur)
      cm.indentLine(cur, "smart");
    /* cm.setSelection(from, cm.getCursor(false)); */
  });
});
